package com.ziyueyuwen.xiniao.thirdpart.util;


import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.dingtalk.api.DefaultDingTalkClient;
import com.dingtalk.api.DingTalkClient;
import com.dingtalk.api.request.*;
import com.dingtalk.api.response.*;
import com.suyeer.cache.RedisUtil;
import com.suyeer.cache.RedisUtil;
import com.taobao.api.ApiException;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.List;

import static com.ziyueyuwen.xiniao.thirdpart.util.DingTalkConstUtil.*;


/**
 * @author wancheng  on 2018/7/17.
 * 钉钉api 参考
 * https://open-doc.dingtalk.com/microapp/serverapi2/dubakq
 * https://open-doc.dingtalk.com/docs/doc.htm?spm=a219a.7629140.0.0.SUkD4p&treeId=366&articleId=104945&docType=1#s4
 */
public class DingTalkUtil {

    private static final String KEY_DING_TALK_ACCESS_TOKEN = "KEY_DING_TALK_ACCESS_TOKEN";

    private static final String KEY_DING_TALK_CORP_ACCESS_TOKEN = "KEY_DING_TALK_CORP_ACCESS_TOKEN";

    private static final String KEY_DING_TALK_CORP_JSAPI_TICKET = "KEY_DING_TALK_CORP_JSAPI_TICKET";

    private static final Integer ACCESS_TOKEN_VALID_SECOND = 6000;

    private static final Logger logger = LoggerFactory.getLogger(DingTalkUtil.class);

    /**
     * User: jun
     * Date: 2018/7/30
     * Desc: 获取钉钉AccessToken
     */
    public static String getAppAccessToken() {
        String accessToken = null;
        try {
            accessToken = RedisUtil.get(KEY_DING_TALK_ACCESS_TOKEN);
        } catch (Exception e) {
            e.printStackTrace();
        }
        if (StringUtils.isNotBlank(accessToken)) {
            logger.info("KEY_DING_TALK_ACCESS_TOKEN: {}", accessToken);
            return accessToken;
        }
        try {
            return getAccessTokeFromDingTalkAndSave();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * User: jun
     * Date: 2018/7/30
     * Desc: 获取钉钉AccessToken
     */
    public static String getCorpAccessToken() {
        String accessToken = null;
        try {
            accessToken = RedisUtil.get(KEY_DING_TALK_CORP_ACCESS_TOKEN);
        } catch (Exception e) {
            e.printStackTrace();
        }
        if (StringUtils.isNotBlank(accessToken)) {
            logger.info("KEY_DING_TALK_CORP_ACCESS_TOKEN: {}", accessToken);
            return accessToken;
        }
        return getAccessToken(DINGTALK_CORPSECRET).getAccessToken();
    }

    /**
     * 获取JsapiTicket
     *
     * @return
     */
    public static String getJsapiTicket() {
        String jsapiTicket = null;
        try {
            jsapiTicket = RedisUtil.get(KEY_DING_TALK_CORP_JSAPI_TICKET);
        } catch (Exception e) {
            e.printStackTrace();
        }
        if (StringUtils.isNotBlank(jsapiTicket)) {
            logger.info("KEY_DING_TALK_CORP_JSAPI_TICKET: {}", jsapiTicket);
            return jsapiTicket;
        }
        String accessToken = getCorpAccessToken();
        DingTalkClient client = new DefaultDingTalkClient(SERVER_GET_JSAPI_TICKET);
        OapiGetJsapiTicketRequest request = new OapiGetJsapiTicketRequest();
        request.setHttpMethod(GET);
        OapiGetJsapiTicketResponse response = new OapiGetJsapiTicketResponse();
        try {
            response = client.execute(request, accessToken);
        } catch (ApiException e) {
            e.printStackTrace();
        }
        try {
            RedisUtil.set(KEY_DING_TALK_CORP_JSAPI_TICKET, response.getTicket(), ACCESS_TOKEN_VALID_SECOND);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return response.getTicket();

    }

    /**
     * User: jun
     * Date: 2018/7/30
     * Desc: 请求钉钉服务器, 获取AccessToken, 并保存到缓存
     */
    public static synchronized String getAccessTokeFromDingTalkAndSave() throws Exception {
        String accessToken = RedisUtil.get(KEY_DING_TALK_ACCESS_TOKEN);
        if (StringUtils.isNotBlank(accessToken)) {
            return accessToken;
        }
        DefaultDingTalkClient client = new DefaultDingTalkClient(DINGTALK_APP_TOKEN_URL);
        OapiGettokenRequest request = new OapiGettokenRequest();
        request.setAppkey(DINGTALK_APP_KEY);
        request.setAppsecret(DINGTALK_APPSECRET);
        request.setHttpMethod(GET);
        OapiGettokenResponse response;
        try {
            response = client.execute(request);
            accessToken = response.getAccessToken();
            if (StringUtils.isBlank(accessToken)) {
                throw new Exception("钉钉返回值错误!");
            }
            RedisUtil.set(KEY_DING_TALK_ACCESS_TOKEN, accessToken, ACCESS_TOKEN_VALID_SECOND);
            return accessToken;
        } catch (Exception e) {
            logger.error("获取钉钉AccessToken失败, 钉钉返回信息: {}, 失败信息: {}",
                    JSON.toJSONString(request),
                    e.getMessage());
            throw new Exception("获取钉钉AccessToken失败!");
        }
    }

    /**
     * 获取用户授权的持久授权码
     * 持久授权码目前无过期时间，可反复使用，参数code只能使用一次。
     *
     * @param code
     * @return {
     * "errcode": 0,
     * "errmsg": "ok",
     * "openid": "liSii8KCxxxxx",
     * "persistent_code": "dsa-d-asdasdadHIBIinoninINIn-ssdasd",
     * "unionid": "7Huu46kk"
     * }
     */
    public static OapiSnsGetPersistentCodeResponse getPersistentCode(String code) throws Exception {
        String accessToken = getAppAccessToken();
        DingTalkClient client = new DefaultDingTalkClient(APP_GET_PERSISTENT_CODE);
        OapiSnsGetPersistentCodeRequest request = new OapiSnsGetPersistentCodeRequest();
        request.setTmpAuthCode(code);
        OapiSnsGetPersistentCodeResponse response = null;
        try {
            response = client.execute(request, accessToken);
        } catch (ApiException e) {
            e.printStackTrace();
        }
        return response;
    }

    /**
     * 获取用户授权的SNS_TOKEN
     * 在获得钉钉用户的持久授权码后，通过以下接口获取该用户授权的SNS_TOKEN，此token的有效时间为2小时，重复获取不会续期。
     *
     * @param openId         用户的openid
     * @param persistentCode 用户授权给钉钉开放应用的持久授权码
     * @param token          开放应用的token
     * @return {
     * "errcode": 0,
     * "errmsg": "ok",
     * "expires_in": 7200,
     * "sns_token": "c76dsc87ds6c876sd87csdcxxxxx"
     * }
     */
    public static OapiSnsGetSnsTokenResponse getSnsToken(String openId, String persistentCode, String token) {
        DingTalkClient client = new DefaultDingTalkClient(APP_GET_SNS_TOKEN);
        OapiSnsGetSnsTokenRequest request = new OapiSnsGetSnsTokenRequest();
        request.setOpenid(openId);
        request.setPersistentCode(persistentCode);
        OapiSnsGetSnsTokenResponse response = null;
        try {
            response = client.execute(request, token);
        } catch (ApiException e) {
            e.printStackTrace();
        }
        return response;
    }

    /**
     * 获取用户授权的个人信息
     * 在获得钉钉用户的SNS_TOKEN后，通过以下接口获取该用户的个人信息。
     *
     * @param snsToken 用户授权给开放应用的token
     * @return {
     * "errcode": 0,
     * "errmsg": "ok",
     * "user_info": {
     * "nick": "张三",
     * "openid": "liSii8KCxxxxx",
     * "unionid": "7Huu46kk"
     * }
     * }
     */
    public static OapiSnsGetuserinfoResponse getuserinfo(String snsToken) {
        DingTalkClient client = new DefaultDingTalkClient(APP_GET_USER_INFO);
        OapiSnsGetuserinfoRequest request = new OapiSnsGetuserinfoRequest();
        request.setSnsToken(snsToken);
        request.setHttpMethod(GET);
        OapiSnsGetuserinfoResponse response = null;
        try {
            response = client.execute(request);
        } catch (ApiException e) {
            e.printStackTrace();
        }
        return response;
    }

    /**
     * CORPID获取钉钉开放应用的ACCESS_TOKEN
     *
     * @return
     */
    public static OapiGettokenResponse getAccessToken(String corpSecret) {
        DingTalkClient client = new DefaultDingTalkClient(SERVER_TOKEN_URL);
        OapiGettokenRequest request = new OapiGettokenRequest();
        request.setCorpid(DINGTALK_CORPID);
        request.setCorpsecret(corpSecret);
        request.setHttpMethod(GET);
        OapiGettokenResponse response = null;
        try {
            response = client.execute(request);
            try {
                RedisUtil.set(KEY_DING_TALK_CORP_ACCESS_TOKEN, response.getAccessToken(), ACCESS_TOKEN_VALID_SECOND);
            } catch (Exception e) {
                e.printStackTrace();
            }
        } catch (ApiException e) {
            e.printStackTrace();
        }
        return response;
    }

    /**
     * 获取改token的授权信息
     *
     * @return
     */
    public static OapiAuthScopesResponse getAuthScopes() {
        String accessToken = getAppAccessToken();
        DingTalkClient client = new DefaultDingTalkClient(SERVER_AUTH_SCOPES);
        OapiAuthScopesRequest request = new OapiAuthScopesRequest();
        request.setHttpMethod(GET);
        OapiAuthScopesResponse response = null;
        try {
            response = client.execute(request, accessToken);
        } catch (ApiException e) {
            e.printStackTrace();
        }
        return response;
    }

    /**
     * 获取部门员工列表（详情）
     *
     * @param accessToken
     * @return
     */
    public static OapiUserListResponse getUserList(Long departmentId) {
        String accessToken  = getAppAccessToken();
        DingTalkClient client = new DefaultDingTalkClient(SERVER_GET_USER_LIST);
        OapiUserListRequest request = new OapiUserListRequest();
        request.setDepartmentId(departmentId);
        request.setHttpMethod(GET);
        OapiUserListResponse response = null;
        try {
            response = client.execute(request, accessToken);
        } catch (ApiException e) {
            e.printStackTrace();
        }
        return response;
    }

    /**
     * 发送文本类消息
     *
     * @param accessToken
     * @param agentId
     * @param userIds
     * @param content
     * @return
     */
    public static OapiMessageCorpconversationAsyncsendV2Response sendTextMsg(String accessToken, Integer agentId, String userIds, String content) {
        DingTalkClient client = new DefaultDingTalkClient(SERVER_SEND_MSG);
        OapiMessageCorpconversationAsyncsendV2Request request = new OapiMessageCorpconversationAsyncsendV2Request();
        request.setUseridList(userIds);
        request.setAgentId(Long.valueOf(agentId));
        request.setToAllUser(false);
        OapiMessageCorpconversationAsyncsendV2Request.Msg msg = new OapiMessageCorpconversationAsyncsendV2Request.Msg();
        msg.setMsgtype("text");
        msg.setText(new OapiMessageCorpconversationAsyncsendV2Request.Text());
        msg.getText().setContent(content);
        request.setMsg(msg);
        OapiMessageCorpconversationAsyncsendV2Response response = null;
        try {
            response = client.execute(request, accessToken);
        } catch (ApiException e) {
            e.printStackTrace();
        }
        return response;
    }

    /**
     * 获取子部门id列表
     *
     * @param accessToken
     * @param parentId
     * @return
     */
    public static OapiDepartmentListIdsResponse getDepartmentChildIds(String accessToken, String parentId) {
        DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/department/list_ids");
        OapiDepartmentListIdsRequest request = new OapiDepartmentListIdsRequest();
        request.setId(parentId);
        request.setHttpMethod(GET);
        OapiDepartmentListIdsResponse response = null;
        try {
            response = client.execute(request, accessToken);
        } catch (ApiException e) {
            e.printStackTrace();
        }
        return response;
    }

    /**
     * 获取部门列表
     *
     * @param accessToken
     * @param parentId
     * @return {
     * "errcode": 0,
     * "errmsg": "ok",
     * "department": [
     * {
     * "id": 2,
     * "name": "钉钉事业部",
     * "parentid": 1,
     * "createDeptGroup": true,
     * "autoAddUser": true
     * },
     * {
     * "id": 3,
     * "name": "服务端开发组",
     * "parentid": 2,
     * "createDeptGroup": false,
     * "autoAddUser": false
     * }
     * ]
     * }
     */
    public static OapiDepartmentListResponse getDepartmentChildList( String parentId) {
        String accessToken = getAppAccessToken();
        DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/department/list");
        OapiDepartmentListRequest request = new OapiDepartmentListRequest();
        request.setId(parentId);
        request.setHttpMethod(GET);
        request.setFetchChild(true);
        OapiDepartmentListResponse response = null;
        try {
            response = client.execute(request, accessToken);
        } catch (ApiException e) {
            e.printStackTrace();
        }
        return response;
    }

    /**
     * 获取角色列表
     *
     * @param accessToken
     * @return
     */
    public static OapiRoleListResponse getRole(String accessToken) {
        DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/role/list");
        OapiRoleListRequest request = new OapiRoleListRequest();
        request.setOffset(0L);
        request.setSize(10L);

        OapiRoleListResponse response = null;
        try {
            response = client.execute(request, accessToken);
        } catch (ApiException e) {
            e.printStackTrace();
        }
        return response;
    }

    public static OapiRoleSimplelistResponse getRoleUserList(Long roleId, String accessToken) {
        DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/role/simplelist");
        OapiRoleSimplelistRequest request = new OapiRoleSimplelistRequest();
        request.setRoleId(roleId);
        request.setOffset(0L);
        request.setSize(10L);

        OapiRoleSimplelistResponse response = null;
        try {
            response = client.execute(request, accessToken);
        } catch (ApiException e) {
            e.printStackTrace();
        }
        return response;
    }

    /**
     * 获取部门信息
     *
     * @param deptId
     * @param accessToken
     * @return
     */
    public static OapiDepartmentGetResponse getDeptInfo(Long deptId, String accessToken) {
        DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/department/get");
        OapiDepartmentGetRequest request = new OapiDepartmentGetRequest();
        request.setId(String.valueOf(deptId));
        request.setHttpMethod(GET);
        OapiDepartmentGetResponse response = null;
        try {
            response = client.execute(request, accessToken);
        } catch (ApiException e) {
            e.printStackTrace();
        }
        return response;
    }

    /**
     * 钉钉E应用登录通过code获取钉钉用户信息
     *
     * @param code
     * @return
     */
    public static OapiUserGetuserinfoResponse getUserInfo(String code) {
        DingTalkClient client = new DefaultDingTalkClient(APP_E_PART_GET_USER_INFO_URL);
        OapiUserGetuserinfoRequest request = new OapiUserGetuserinfoRequest();
        request.setCode(code);
        request.setHttpMethod(GET);
        OapiUserGetuserinfoResponse response = null;
        try {
            response = client.execute(request, getAppAccessToken());
        } catch (Exception e) {
            e.printStackTrace();
        }
        return response;
    }

    /**
     * 获取用户请假审批实例ID列表
     *
     * @param startTime
     * @param endTime
     * @param userId
     * @param processCode
     * @return
     */
    public static List<String> getProcessInstanceIds(Long startTime, Long endTime, String userId, String processCode) {
        DingTalkClient client = new DefaultDingTalkClient(SERVER_USER_PROCESS_URL);
        OapiProcessinstanceListidsRequest req = new OapiProcessinstanceListidsRequest();
        req.setProcessCode(processCode);
        req.setStartTime(startTime);
        req.setEndTime(endTime);
        req.setSize(10L);
        req.setCursor(0L);
        req.setUseridList(userId);
        String accessToken = DingTalkUtil.getCorpAccessToken();
        OapiProcessinstanceListidsResponse response = null;
        try {
            response = client.execute(req, accessToken);
        } catch (ApiException e) {
            e.printStackTrace();
        }
        List<String> res = new ArrayList<>();
        if (response == null) {
            res = new ArrayList<>();
        } else {
            res = response.getResult().getList();
        }
        return res;
    }

    /**
     * 获取请假实例
     *
     * @param processInstanceId
     * @return eg:{
     * "compressedValue":"",
     * "extension":"{"tag":"调休"}",
     * "unit":"HOUR",
     * "pushTag":"请假",
     * "isNaturalDay":false,
     * "detailList":[
     * {
     * "classInfo":{
     * "hasClass":false,
     * "sections":[
     * {
     * "endAcross":0,
     * "startTime":1543883400000,
     * "endTime":1543915800000,
     * "startAcross":0
     * }
     * ]
     * },
     * "workDate":1543852800000,
     * "isRest":false,
     * "workTimeMinutes":480,
     * "approveInfo":{
     * "fromAcross":0,
     * "toAcross":0,
     * "fromTime":1543888800000,
     * "durationInDay":0.81,
     * "durationInHour":6.5,
     * "toTime":1543915800000
     * }
     * }
     * ],
     * "durationInDay":0.81,
     * "isModifiable":true,
     * "durationInHour":6.5
     * }
     */
    public static JSONObject getProcessInstanceById(String processInstanceId) {
        DingTalkClient client = new DefaultDingTalkClient(SERVER_USER_PROCESS_INSTANCE_URL);
        OapiProcessinstanceGetRequest request = new OapiProcessinstanceGetRequest();
        request.setProcessInstanceId(processInstanceId);
        String accessToken = DingTalkUtil.getCorpAccessToken();
        OapiProcessinstanceGetResponse response = null;
        try {
            response = client.execute(request, accessToken);
        } catch (ApiException e) {
            e.printStackTrace();
        }
        if (response.getProcessInstance() != null && AGREE.equals(response.getProcessInstance().getResult())) {
            String extValue = response.getProcessInstance().getFormComponentValues().get(0).getExtValue();
            JSONObject jsonObject = JSON.parseObject(extValue);
            jsonObject.put(USER_ID, response.getProcessInstance().getOriginatorUserid());
            return jsonObject;
        }
        return null;
    }

    public static OapiProcessinstanceListResponse getProcessInstance(Long startTime, Long endTime, String processCode) {
        DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/processinstance/list");
        OapiProcessinstanceListRequest req = new OapiProcessinstanceListRequest();
        req.setProcessCode(processCode);
        req.setStartTime(startTime);
        req.setEndTime(endTime);
        req.setSize(10L);
        req.setCursor(0L);
        String accessToken = DingTalkUtil.getCorpAccessToken();
        OapiProcessinstanceListResponse response = null;
        try {
            response = client.execute(req, accessToken);
        } catch (ApiException e) {
            e.printStackTrace();
        }
        return response;
    }
}
